#include "server.h"

void chat_room::join(chat_session_ptr participant) {
    participants_.insert(participant);
    
    // 给新加入者广播一遍历史消息
    for(const auto& msg: recent_msgs_) {
        participant->deliver(msg);
    }
}

void chat_room::leave(chat_session_ptr participant) {
    participants_.erase(participant);
}

// 消息分发函数
void chat_room::deliver(const chat_message& msg) {
    recent_msgs_.push_back(msg);
    // recent_msgs_调整到最大值
    while(recent_msgs_.size() > max_recent_msgs) {
        recent_msgs_.pop_front();
    }

    // 给每个群聊参与者群发消息
    for(auto & participant: participants_) {
        participant->deliver(msg);
    }
}




chat_server::chat_server(boost::asio::io_service& io_service, 
                    const tcp::endpoint& endpoint): acceptor_(io_service, endpoint), 
                                                    socket_(io_service){
                                                        do_accept();
                                                    }
        
        // 接收来自客户端的连接的函数
void chat_server::do_accept() {
        acceptor_.async_accept(
                    socket_, 
                    [this] (boost::system::error_code ec) {
                            // 如果接收连接成功，没有错误
                        if(!ec) {
                            auto session = std::make_shared<chat_session>(std::move(socket_),
                                    room_
                                );

                            session->start();
                        } 

                        // 无论成功或失败，都继续接受连接
                    do_accept();
                    }
                );
    }

chat_session::chat_session(tcp::socket socket, chat_room& room):socket_(std::move(socket)), room_(room) {}

void chat_session::start(){
    room_.join(shared_from_this());
    // 启动服务时开始读取消息头
    do_read_header();
}

void chat_session::deliver(const chat_message& msg) {
    bool write_in_progress = !write_msgs_.empty();
        write_msgs_.push_back(msg);            

        // 为了保护do_write线程里面的deque，避免两个线程同时写
        if(!write_in_progress) {
                do_write();
        }
}

void chat_session::do_read_header(){
        auto self(shared_from_this());

        boost::asio::async_read(
                    socket_,
                    boost::asio::buffer(read_msg_.data(), chat_message::header_length),
                    [this, self] (boost::system::error_code ec, std::size_t length) {
                        // 头部解析成功，获取到body_length
                        if(!ec && read_msg_.decode_header()) {
                            do_read_body();
                        } else {
                            room_.leave(shared_from_this());
                            }
                    }
                );
    }


void chat_session::do_read_body(){
    auto self(shared_from_this());

    boost::asio::async_read(
        socket_,
        boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
            [this, self] (boost::system::error_code ec, std::size_t length) {
                // 如果读取消息成功，没有error
            if(!ec) {
                    // room_的deliver msg，会先更新recent_message queue,
                    // 然后调用各个Session的Deliver message
                    // 将消息发给对应的client 
                    room_.deliver(read_msg_);
                    // 接着读头，形成事件循环
                    do_read_header();
                    }else {
                    room_.leave(shared_from_this());
                    }
                }
            );
}

void chat_session::do_write(){
    auto self(shared_from_this());
    boost::asio::async_write(
            socket_,
            boost::asio::buffer(write_msgs_.front().data(), write_msgs_.front().length()),
            [this, self] (boost::system::error_code ec, std::size_t length) {
                // 如果写队头信息成功，没有错误    
                if(!ec) {

                    write_msgs_.pop_front();
                    // 如果还有得写，就接着写
                    if(!write_msgs_.empty()) {
                        do_write();
                    }
                 }else {
                    room_.leave(shared_from_this());
                }
            }
        );
}